﻿/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is AST'r Framework.
  
  The Initial Developer of the Original Code is
  ALCARAZ Marc (aka eKameleon) <vegas@ekameleon.net>.
  Portions created by the Initial Developer are Copyright (C) 2004-2007
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
 */

import ewhiteboard.display.whiteboard.WhiteBoardType;

import lunas.display.components.AbstractComponent;

import pegas.draw.Canvas;
import pegas.geom.Point;
import pegas.geom.Rectangle;
import pegas.geom.Trigo;
import pegas.maths.Range;

import vegas.events.Delegate;

class ewhiteboard.display.WhiteBoard extends AbstractComponent {

	// ----o Constructor

	public function WhiteBoard () {

		
		name = _name == null ? "_DEFAULT_" : _name ;
		prefix = "WhiteBoard." + this.name + ".";
		
		// ----
		
		Key.addListener(this) ;
		
		var initBackground:Object = {
			fc:0, fa:0 , ep:0, lc:0 , la:0
		};
		
		var bg:MovieClip = createChild(Rectangle, "background_mc", 0, initBackground) ; //background_mc ;
		bg.useHandCursor = true ;
		bg.onRollOver = function(){} ;

		var initDrawinArea:Object = {
			fc:0xCCCCCC, fa:0 , ep:0, lc:0xCCCCCC, la:0
		};

		var da:MovieClip = createChild(Rectangle, "drawingArea_mc", 1, initDrawinArea) ;
		da.useHandCursor = false ;
		da.onPress = Delegate.create(this, drawPress) ;
		da.onRelease = da.onReleaseOutside = Delegate.create(this, drawRelease) ;
		
		var co:MovieClip = createEmptyMovieClip("container_mc", 3) ;

		// Create a clip for drawing the bounding box around a shape
		var sh:MovieClip = createEmptyMovieClip("shapeSelect_mc", 4);
		sh._x = da._x ;
		sh._y = da._y ;

		var te:MovieClip = createEmptyMovieClip("tempLine_mc", 5) ;
		te._x = da._x ;
		te._y = da._y ;

		setActiveColor(0x000000) ;
		setBackgroundPolicy(WhiteBoard.ON) ;
		setTool(WhiteBoardType.SELECTOR) ;
		update() ;
		
	}
	
	public static var __path__:String = "ewhiteboard.display.WhiteBoard" ;
	
	// ----o Static Properties
	
	public static var OFF:Number = 0 ;
	public static var ON:Number = 1 ;
	
	// ----o Public Properties
	
	public var name:String ;
	public var prefix:String ;
	
	public var activeColor:Number ;
	public var activeTool:Number ;
	public var selectedShape:MovieClip ;
	public var selectAlpha:Number = 50 ;
	
	public var nc:NetConnection ;
	public var so:SharedObject ;
	
	public var background_mc:MovieClip ;
	public var container_mc:MovieClip ;
	public var drawingArea_mc:MovieClip ;
	public var shapeSelect_mc:MovieClip ;
	public var tempLine_mc:MovieClip ;
	public var menu_mc:MovieClip ;
	
	public var p:Point ;
	public var memory:Array ;
	public var maxPoint:Number = 200 ;

	// ----o Public Methods
	
	public function clear():Void {
		var o = so.data ;
		for (var prop in o) {
			o[prop] = null ;
		}
	}
	
	public function close():Void {
		nc.call( this.prefix + "close", null) ;
		delete so.onSync ;
		so.close() ;
		so = null ;
		nc.WhiteBoard[name] = null;
		nc = null;
	}
	
	public function connect(connector):Void {
		if (connector.isConnected) {
			nc = connector ;
			if ( nc.WhiteBoard == null ) nc.WhiteBoard = {} ;
			nc.WhiteBoard[name] = this ;
			so = SharedObject.getRemote( prefix + "whiteboard", nc.uri, false) ;
			so.onSync = Delegate.create(this, _onSync) ;
			so.connect(nc);
			this.nc.call( this.prefix + "connect", null) ;
		}
	}
	
	public function draw():Void {
		_xscale = 100 ;
		_yscale = 100 ;
		drawingArea_mc.setSize(_w, _h) ;
		background_mc.setSize(_w, _h) ;
		menu_mc._x = 0;
		menu_mc._y = _h - 40 ;
	}

	public function setActiveColor(color:Number):Void {
		activeColor = color ;
	}
	
	public function setBackground(color:Number, alpha:Number):Void {
		background_mc.refresh({ fc : color , lc : color , fa : alpha , la : alpha }) ;
	}
	
	public function setBackgroundPolicy(mode:Number):Void {
		background_mc.enabled = (mode == WhiteBoard.ON) ;
	}

	public function setTool(tool:Number):Void {
		activeTool = tool ;
	}

	public function showTools(flag:Boolean):Void {
		menu_mc._visible = flag ;
	}
	
	public function viewDestroyed():Void {
		close() ;
	}
	
	// ----o Private Properties

	private var activeCaretIndex:Number ;
	private var _idActive:Number ;
	private var lastX:Number ;
	private var lastY:Number ;
	private var _startPoint:Point ;
	private var _endPoint:Point ;
	
	private var _w:Number = 450 ;
	private var _h:Number = 270 ;
	
	// ----o Private Methods

	private function _changeField(field:TextField, name:String) {
		name = name.substr(0, name.length - 3 ) ; // MM method - change !!
		so.data[name].text = field.text ;
		field.hScroll = field.maxhscroll ;
		activeCaretIndex = Selection.getCaretIndex() ;
	}

	private function drawPress():Void {
		
		var shapeData:Object ;
		
		switch (activeTool) {
			
			case WhiteBoardType.FREEHAND :
				
				var x,y:Number ;
				var cpt:Number = 0 ;
				var area = drawingArea_mc ;
				p = new Point(area._xmouse, area._ymouse) ;
				var mc:MovieClip = tempLine_mc ;
				mc._x = p.x ;
				mc._y = p.y ;
				memory = [] ;
				memory.push(["S", [4, activeColor, 100]]) ;
				mc.lineStyle(4, activeColor, 100) ;
				onMouseMove = function () {
					if ( cpt++ < this.maxPoint ) {
						x = mc._xmouse ;
						y = mc._ymouse ;
						this.memory.push( ['L',[x,y]]) ;
						mc.lineTo(x,y) ;
					}
				};
								
				break ;
			
			case WhiteBoardType.ENDPOINT : 
			case WhiteBoardType.STARTPOINT :
			case WhiteBoardType.BOTHPOINTS :
			
				var mc:MovieClip = tempLine_mc ;
							
				mc.x1 = drawingArea_mc._xmouse ;
				mc.y1 = drawingArea_mc._ymouse ;
				mc.type = activeTool ;
				mc.lineColor = activeColor;
				
				onMouseMove = Delegate.create(this, drawTempLine) ;
				
				break ;
				
			case WhiteBoardType.PLAINTEXT :
				
				shapeData = {
					x : drawingArea_mc._xmouse ,
					y : drawingArea_mc._ymouse ,
					text : "New Text" ,
					shapeColor:activeColor ,
					shape:WhiteBoardType.PLAINTEXT 
				};
				nc.call( prefix + "newShape", null, shapeData ) ;
				break ;
			
			case WhiteBoardType.TEXTBOX :
				
				shapeData = {					
					x : drawingArea_mc._xmouse ,
					y : drawingArea_mc._ymouse ,
					text : "New Box" ,
					shapeColor : activeColor ,
					shape : activeTool
				};
				nc.call( prefix + "newShape", null, shapeData) ;
				break;
		}

	}
	
	private function drawRelease():Void {
		// Mouse was released after previously pressing on the drawing area
		delete onMouseMove ;
		var mc:MovieClip = tempLine_mc ;
		mc.clear() ;
		mc._x = 0 ;
		mc._y = 0 ;
		
		switch (activeTool) {
			case WhiteBoardType.FREEHAND :
				var shapeData = {
					shape : WhiteBoardType.FREEHAND , 
					x : p.x ,
					y : p.y ,
					canvas : memory
				};
				
				nc.call( prefix + "newShape", null, shapeData ) ;
				
				break ;
			
			case WhiteBoardType.BOTHPOINTS :
			case WhiteBoardType.STARTPOINT :
			case WhiteBoardType.ENDPOINT :
				var shapeData = {
					shape : activeTool , 
					x1 : tempLine_mc.x1 ,
					y1 : tempLine_mc.y1 ,
					x2 : tempLine_mc.x2 ,
					y2 : tempLine_mc.y2 ,
					lineType : tempLine_mc.lineType ,
					lineColor : tempLine_mc.lineColor
				};

				nc.call(prefix + "newShape", null, shapeData) ;
				break ;
			
		}
	}

	private function drawShape( shapeData, shapeType, success:Boolean):Void {
		
	
		var newShape:MovieClip = container_mc.createEmptyMovieClip( shapeData.clip , shapeData.depth ) ;
		
		newShape._x = drawingArea_mc._x ;
		newShape._y = drawingArea_mc._y ;
		
		var type = shapeType ;
		switch (type) {
			
			case WhiteBoardType.FREEHAND :
			
				newShape.type = WhiteBoardType.FREEHAND ;
				newShape._x = shapeData.x ;
				newShape._y = shapeData.y ;
			
				var mc:MovieClip = newShape.createEmptyMovieClip("canvas_mc", 1) ;
			
				var c:Canvas = new Canvas(mc) ;
				c.setData(shapeData.canvas) ;
				c.draw() ;
			
				var bounds = mc.getBounds(newShape) ;
				var p0:Point = new Point(bounds.xMin, bounds.yMin) ;
				var p1:Point = new Point(bounds.xMax, bounds.yMax) ;
				
				mc._x = Math.abs(p0.x) ;
				mc._y = Math.abs(p0.y) ;
				
				newShape._x -= mc._x ;
				newShape._y -= mc._y ;
				
				bounds = mc.getBounds(newShape) ;
				p0 = new Point(bounds.xMin, bounds.yMin) ;
				p1 = new Point(bounds.xMax, bounds.yMax) ;
				
				var dragger:MovieClip = newShape.createEmptyMovieClip("dragger_mc", 10);
				//dragger.lineStyle(1, 0x0000ff);
				dragger.beginFill(0, 0);
				dragger.moveTo(p0.x, p0.y) ;
				dragger.lineTo(p1.x, p0.y);
				dragger.lineTo(p1.x, p1.y);
				dragger.lineTo(p0.x, p1.y);
				dragger.lineTo(p0.x, p0.y);
				dragger.endFill();
				
				var w = newShape._width ;
				var h = newShape._height ;
				
				mc.onPress = Delegate.create(this, shapePress, newShape) ;
				mc.onReleaseOutside = Delegate.create(this, shapeRelease, newShape) ;
				mc.onRelease = mc.onReleaseOutside ;
				
				break ;
				
			case WhiteBoardType.ENDPOINT :
			case WhiteBoardType.STARTPOINT :
			case WhiteBoardType.BOTHPOINTS :
			
				newShape.x1 = shapeData.x1 ;
				newShape.y1 = shapeData.y1 ;
				newShape.x2 = shapeData.x2 ;
				newShape.y2 = shapeData.y2 ;
				newShape.type = type ;
				
				newShape.lineColor = shapeData.lineColor ;
				newShape.lineStyle(4, newShape.lineColor) ;
				newShape.moveTo(newShape.x1, newShape.y1) ;
				newShape.lineTo(newShape.x2, newShape.y2) ;
				
				var angle = Trigo.angleOfLine(newShape.x1, newShape.y1, newShape.x2, newShape.y2);
				var offsetA = Trigo.polarToCartesian( { r : 10, t : angle + 135 } );
				var offsetB = Trigo.polarToCartesian( { r : 10, t : angle - 135 } );
				
				if (type == WhiteBoardType.ENDPOINT || type == WhiteBoardType.BOTHPOINTS) {
					newShape.lineTo(newShape.x2 + offsetA.x, newShape.y2 + offsetA.y);
					newShape.moveTo(newShape.x2, newShape.y2);
					newShape.lineTo(newShape.x2 + offsetB.x, newShape.y2 + offsetB.y);
				}
			
				if (type == WhiteBoardType.STARTPOINT || type == WhiteBoardType.BOTHPOINTS) {
					newShape.moveTo(newShape.x1, newShape.y1);
					newShape.lineTo(newShape.x1 - offsetB.x, newShape.y1 - offsetB.y);
					newShape.moveTo(newShape.x1, newShape.y1);
					newShape.lineTo(newShape.x1 - offsetA.x, newShape.y1 - offsetA.y);
				}
	
				newShape.onPress = Delegate.create(this, shapePress, newShape) ;
				newShape.onReleaseOutside = Delegate.create(this, shapeRelease, newShape) ;
				newShape.onRelease = newShape.onReleaseOutside ;
				
				break ;
			
			case WhiteBoardType.PLAINTEXT :
			case WhiteBoardType.TEXTBOX :
				
				newShape.createTextField("shape_txt", 20, 3, 3, 50, 20);
				
				var rx:Range = new Range(0, w) ;
				var ry:Range = new Range(0, h) ;
				
				newShape._x = rx.clamp(shapeData.x) ;
				newShape._y = ry.clamp(shapeData.y) ;
				
				var field:TextField = newShape.shape_txt ;
							
				var format:TextFormat = new TextFormat();
				//format.align = "center";
				format.bold = true;
				format.font = "Arial";
				format.size = 17 ;
				format.leftMargin = 4 ;
				format.rightMargin = 4 ;
				
				field.setNewTextFormat(format);
				
				if (type == WhiteBoardType.PLAINTEXT) 
				{
					field.autoSize = "left";
					field.textColor = shapeData.shapeColor ;
				}		
				else if (type == WhiteBoardType.TEXTBOX) 
				{
					field.autoSize = "left" ;
					field.background = true ;
					field.backgroundColor = (shapeData.shapeColor != 0) ? shapeData.shapeColor : 0xffffff ;
					field.border = true ;
					field.multiline = true ;
				}
			
				field.type = "input" ;
				field.text = shapeData.text ;
				
				field.onChanged = Delegate.create(this, _changeField, shapeData.clip) ;
			
				// Set focus if the user is editing this shape
				if (success) 
				{
					Selection.setFocus(field);
					Selection.setSelection(activeCaretIndex, activeCaretIndex);
				}

				// Make dragger box
				var dragger:MovieClip = newShape.createEmptyMovieClip("dragger_mc", 10);
				
				//dragger.lineStyle(1, 0x0000ff) ;
				dragger.beginFill(0, 0);
				
				var w:Number = field._width + 6 ; 
				var h:Number = field._height + 10 ;
				dragger.lineTo(w, 0);
				dragger.lineTo(w, h);
				dragger.lineTo(0, h);
				dragger.lineTo(0, 0);
				dragger.endFill() ;
				
				dragger.onPress = Delegate.create(this, shapePress, newShape) ;
				dragger.onRelease = Delegate.create(this, shapeRelease, newShape) ;
				dragger.onReleaseOutside = dragger.onRelease ;
				
				break ;
		}
	}

	private function drawTempLine(color:Number):Void { // ??? macromedia no use param in the method
		var line:MovieClip = tempLine_mc ;
		var area:MovieClip = drawingArea_mc ;
		var rx:Range = new Range(0, drawingArea_mc._width) ;
		var ry:Range = new Range(0, drawingArea_mc._height) ;
		var p:Point = new Point(rx.clamp(area._xmouse), ry.clamp(area._ymouse));
		line.x2 = p.x ;
		line.y2 = p.y ;
		line.clear() ;
		line.lineStyle(4, tempLine_mc.lineColor) ;
		line.moveTo(tempLine_mc.x1, this.tempLine_mc.y1) ;
		line.lineTo(tempLine_mc.x2, this.tempLine_mc.y2) ;
	}

	private function _selectTool(ev):Void {
		if (ev.tool == WhiteBoardType.COLOR) {
			setActiveColor(ev.color) ;
		} else {
			setTool(ev.tool) ;
		}
	}

	private function shapePress(shape:MovieClip):Void {
		
		//trace ("isSelected  : " + (activeTool != WhiteBoardType.SELECTED)) ;
		
		if (activeTool != WhiteBoardType.SELECTOR) return ;
		
		selectedShape = shape ;
				
		lastX = drawingArea_mc._xmouse ;
		lastY = drawingArea_mc._ymouse ;
		
		selectedShape = shape ;
		
		var type:Number = shape.type ;
		
		switch (type) {
		
			case WhiteBoardType.FREEHAND :
		
				_startPoint = new Point(shape._x, shape._y) ;
				var p0:Point = new Point(drawingArea_mc._x, drawingArea_mc._y);
				var p1:Point = p0.plusNew( new Point(w - shape._width, h - shape._height) ) ;
				shape.startDrag(false, p0.x , p0.y , p1.x , p1.y) ;
				break ;
			
			case WhiteBoardType.STARTPOINT :
			case WhiteBoardType.ENDPOINT   :
			case WhiteBoardType.BOTHPOINTS :
		
				var p1:Point = new Point(shape.x1 , shape.y1) ;
				var p2:Point = new Point(drawingArea_mc._xmouse , drawingArea_mc._ymouse) ;
				var p3:Point = new Point(shape.x2, shape.y2) ;
				var p4:Point = new Point(drawingArea_mc._xmouse, drawingArea_mc._ymouse) ;
				var distance1:Number = Trigo.distanceP( p1, p2 ) ;
				var distance2:Number = Trigo.distanceP( p3, p4 ) ;
				if (distance1 < distance2) {
					if (type == WhiteBoardType.STARTPOINT) 	{
						shape.type = WhiteBoardType.ENDPOINT ;
					} else if (type == WhiteBoardType.ENDPOINT) {
						shape.type = WhiteBoardType.STARTPOINT ;
					}
					var x2 = shape.x1 ;
					var y2 = shape.y1 ;
					
					shape.x1 = shape.x2 ;
					shape.y1 = shape.y2 ;
					shape.x2 = x2 ;
					shape.y2 = y2 ;
				
				}
				
				tempLine_mc.x1 = shape.x1 ;
				tempLine_mc.y1 = shape.y1 ;
				tempLine_mc.lineType = shape.type ;
				tempLine_mc.lineColor = shape.lineColor ;
				shape.clear();
				tempLine_mc.onMouseMove = Delegate.create(this, drawTempLine) ;
				drawTempLine() ;
			
				break ;
				
			default :
		
				_startPoint = new Point(shape._x, shape._y) ;
				var p0:Point = new Point(drawingArea_mc._x, drawingArea_mc._y);
				var p1:Point = p0.plusNew( new Point(w - shape._width, h - shape._height) ) ;
				shape.startDrag(false, p0.x , p0.y , p1.x , p1.y) ;
				break ;
		}
	}
	
	private function shapeRelease(shape):Void {
		
		//trace ("isSelected  : " + (activeTool != WhiteBoardType.SELECTED)) ;
		
		if (activeTool != WhiteBoardType.SELECTOR) return ;
		
		var shapeName = shape._name.substr(0, shape._name.length - 3);
		var shapeData = so.data[shapeName] ;
		
		shape._visible = false ; // Hide the shape until it's redrawn with the onSync
		
		var type:Number = shape.type ;
		
		switch (type) {
			
			case WhiteBoardType.ENDPOINT :
			case WhiteBoardType.STARTPOINT :
			case WhiteBoardType.BOTHPOINTS :
			
				if (lastX != drawingArea_mc._xmouse || lastY != drawingArea_mc._ymouse) 
				{
					shapeData.x1 = tempLine_mc.x1 ;
					shapeData.y1 = tempLine_mc.y1 ;
					shapeData.x2 = tempLine_mc.x2 ;
					shapeData.y2 = tempLine_mc.y2 ;
					shapeData.type = type ;
				}
				else 
				{
					if(shapeData.uselessProperty != null) 
					{
						shapeData.uselessProperty = !(shapeData.uselessProperty) ;
					}
					else 
					{
						shapeData.uselessProperty = true;
					}
				}
				shapeData.revision ++ ;
				tempLine_mc.clear() ;
				delete tempLine_mc.onMouseMove ;
			
			default :
			
				shape.stopDrag() ;
				var area:MovieClip = drawingArea_mc ;
				_endPoint = new Point (area._xmouse, area._ymouse) ;
				var distance:Number = Point.distance(_startPoint, _endPoint) ;
				if (distance > 0) 
				{
					shapeData.x += (shape._x - _startPoint.x) ;
					shapeData.y += (shape._y - _startPoint.y) ;
					shape._x = _startPoint.x ;
					shape._y = _startPoint.y ;
				}
				shapeData.revision++ ;
		}
	}

	private function onKeyDown():Void {
		// Delete Key Doesn't work in authoring environment, use Ctrl-Delete
		if ( Key.isDown(Key.DELETEKEY)  
				&& activeTool == WhiteBoardType.SELECTOR
					&& selectedShape != null )
		{
			// ---- Delete active shape by removing it from the SharedObject
			var shape = selectedShape ;
			var shapeName = shape._name.substr(0, shape._name.length - 3) ;
			so.data[shapeName] = null ;
			selectedShape = null ;
			shapeSelect_mc.clear() ; // Get rid of bounding box highlight
		}
	} 
		
	private function _onSync(list):Void 
	{
		var l:Number = list.length ;
		for (var i = 0 ; i < list.length; i++) 
		{
			var name = list[i].name ;
			var code = list[i].code ;
			var o = so.data[name] ;
			//trace ("onSync :: " + name + " : " + code + " -> " + o)
			if (code == "delete") 
			{
				container_mc[name + "_mc"].removeMovieClip(); // Shape has been deleted, remove it.
			}
			else 
			{
				drawShape(o, o.shape, code == "success") ; // New/Updated Shape
			}
		}
	}

	
}